/**
 * Validates form elements.
 */
function validateForm(form) {
    var result = true;
    var elements = form.elements;
    for (var i = 0; (i < elements.length) && result; ++i) {
        var element = elements[i];
        result = validateElement(element);
    }
    return result;
}

function validateElement(element) {
    var result = true;
    var nextSibling = element.nextSibling;
    if ((nextSibling != null) && (nextSibling.nodeType == 1) && (nextSibling.tagName == "A")) {
        // validate the field is not null
        if ((nextSibling.className == "nonempty") && (Trim(element.value) == "")) {
            alert(alert_not_empty.replace('<field name>', nextSibling.firstChild.nodeValue));
            result = false;
        }

        // validate the field is not null, same with nonempty validation, but different prompt message
        if ((nextSibling.className == "required") && (Trim(element.value) == "")) {
            alert(alert_is_required.replace('<field name>', nextSibling.firstChild.nodeValue));
            result = false;
        }

        // validate the field is not null nor too long
        if (nextSibling.className == "description") {
            if (Trim(element.value) == "") {
                alert(alert_not_empty.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
            else if (element.value.length > 255) {
                alert(alert_less_char.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
        }

        // no trainling blank character
        if ((nextSibling.className == "generalname") && !isGeneralName(element.value)) {
            alert(alert_no_blank.replace('<field name>', nextSibling.firstChild.nodeValue));
            result = false;
        }

        // validate the field is not null or http://
        if ((nextSibling.className == "http") && ((Trim(element.value) == "") || (Trim(element.value) == "http://"))) {
            alert(alert_not_empty.replace('<field name>', nextSibling.firstChild.nodeValue));
            result = false;
        }

        // validate the field is mail format
        if ((nextSibling.className == "mailformat")) {
            var regstr = /^[\w-]+(\.[\w-]*)*@([\w-]+\.)+[\w-]{2,4}$/;
            if (!regstr.test(element.value)) {
                alert(alert_email_format_incorrect.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
        }

        // validate the field is URL format
        if ((nextSibling.className == "urlformat")) {
            if (!isUrl(element.value)) {
                alert(alert_url_format_incorrect.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
        }

        // validate the field is account number
        if ((nextSibling.className == "accountnumber")) {
            if (Trim(element.value) == "") {
                alert(alert_not_empty.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
            else {
                var reg  =  /^[a-zA-Z0-9_]+?$/;
                if (!reg.test(element.value)) {
                    alert(alert_account_number_incorrect.replace('<field name>', nextSibling.firstChild.nodeValue));
                    result = false;
                }
            }
        }


        // validate the field is date format
        if ((nextSibling.className == "dateformat")) {
            var reg  =  /^(\d{4})-(\d{2})-(\d{2})$/;
            result = (reg.test(element.value));
            if (!reg.test(element.value)) {
                alert(alert_date_format_incorrect.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
            else if (!checkDateValid(element.value)) {
                alert(alert_date_invalid.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
        }

        // validate the field is dates format
        if ((nextSibling.className == "datesformat")) {
            var reg  =  /^(\d{4})-(\d{2})-(\d{2})$/;
            var dates = element.value.split(',');
            for (each in dates) {
                eachDates = dates[each].split(":");
                for (eachDate in eachDates) {
                    var date = eachDates[eachDate];
                    if ((result) && ((!reg.test(date)) || (!checkDateValid(date)))) {
                        alert(alert_dates_invalid.replace('<field name>', nextSibling.firstChild.nodeValue));
                        result = false;
                    }
                }
            }
        }
        
        // validate the field is date format if field is not empty
        if (nextSibling.className == "optionaldateformat") {
            if (Trim(element.value) == '') {
                return true;
            }
            else {
                 var reg = /^(\d{4})-(\d{2})-(\d{2})$/;
                 result = (reg.test(element.value));
                 if (!reg.test(element.value)) {
                     alert(alert_date_format_incorrect.replace('<field name>', nextSibling.firstChild.nodeValue));
                     element.focus();
                     result = false;
                 }
                 else if (!checkDateValid(element.value)) {
                    alert(alert_date_invalid.replace('<field name>', nextSibling.firstChild.nodeValue));
                    result = false;
                }
            }
        }

        // validate the field is username format
        if ((nextSibling.className == "username")) {
            var reg  =  /^[a-zA-Z0-9_\-.]+?$/;
            if (!reg.test(element.value)) {
                alert(alert_letter_format_incorrect.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
            else if(element.value.length < 3) {
                alert(alert_more_char.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
            else if(!isNaN(element.value.charAt(0)) || element.value.charAt(0) == "_") {
                alert(alert_field_format_incorrect.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
        }


        // validate the field is password format.
        if ((nextSibling.className == "password")) {
            if (Trim(element.value) == "") {
                alert(alert_not_empty.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
            else {
                var reg  = /^[\w`~!@#\$%\^&\*\(\)-=\+\\\|\]}[{\'\";:\?\/\.>,<]+?$/;
                if (!reg.test(element.value)) {
                    alert(alert_format_incorrect.replace('<field name>', nextSibling.firstChild.nodeValue));
                    result = false;
                }
                else if (!((Trim(element.value.length) >= 0) && (Trim(element.value.length) <= 50))) {
                    var message = alert_single_length_incorrect.replace('<field name>', nextSibling.firstChild.nodeValue);
                    message = message.replace('<%min_length>', 1);
                    message = message.replace('<%max_length>', 50);
                    alert(message);
                    result = false;
                }
            }
        }

        // validate the field is user account format
        if ((nextSibling.className == "useraccount")) {
            var reg  =  /^[a-zA-Z0-9]+?$/;
            result = (reg.test(element.value));
            if (!reg.test(element.value)) {
                alert(alert_user_account_format_incorrect.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
        }

        // validate the field is zip format
        if ((nextSibling.className == "zipcode")) {
            var reg  =  /^\d{5}(-\d{4})?$/;
            if (!reg.test(element.value)) {
                alert(alert_zip_incorrect.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
        }

        // validate the field is Code format
        if ((nextSibling.className == "code")) {
            var reg  =  /^[0-9]+(\-[0-9]+)?$/;
            result = (reg.test(element.value));
            if (!reg.test(element.value)) {
                alert(alert_code_format_incorrect.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
        }

        // validate the field which is "SSN/Tax ID"
        if ((nextSibling.className == "ssn")) {
            if (Trim(element.value) == "") {
                alert(alert_not_empty.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
            else {
                var reg = /[0-9]|[a-z]|[A-Z]|-/;
                var regNegative = /[\.]|[_]/;
                if (!reg.test(element.value) || regNegative.test(element.value)) {
                    alert(alert_dynamic_incorrect.replace('<field name>', nextSibling.firstChild.nodeValue));
                    result = false;
                }
            }
        }

        // validate the field is Credit Card Number format
        if ((nextSibling.className == "creditcard")) {
            if (Trim(element.value) == "") {
                alert(alert_not_empty.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
            else {
                if (element.form.maskedCardNumber.value != element.value) {
                    var reg = /^[0-9]+?$/;
                    result = reg.test(element.value);
                    if (!result) {
                        alert(alert_credit_incorrect.replace('<field name>', nextSibling.firstChild.nodeValue));
                        result = false;
                    }
                }
            }
        }

        // validate the field is float format
        if ((nextSibling.className == "floatformat")) {
            var regfloat  = /^[0-9]*(\.[0-9]+)?$/;
            if (!element.canBeNull && Trim(element.value) == "") {
                alert(alert_require_float.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
            else if ((element.canBeNull && Trim(element.value) != "") || !element.canBeNull) {
                if (!regfloat.test(element.value)) {
                    alert(alert_require_float.replace('<field name>', nextSibling.firstChild.nodeValue));
                    result = false;
                }
                if (result && !checkRange(element, null)) {
                    result = false;
                }
                else if (result && element.canBeZero) {
                    if (element.value < 0) {
                        alert(alert_require_none_negative.replace('<field name>', nextSibling.firstChild.nodeValue));
                        result = false;
                    }
                }
                else if (result && element.value <= 0 && "maxBidValidation" != nextSibling.id) { //for bug4560, max bid is 0 will be no error message
                    alert(alert_require_positive.replace('<field name>', nextSibling.firstChild.nodeValue));
                    result = false;
                }
                var decimals = Math.round(nextSibling.title);
                if (result && decimals > 0) {
                    var value = element.value;
                    for (var l = 0; l < decimals; l++) {
                        value *= 10;
                    }
                    if (Math.abs(value - Math.round(value)) > 1e-12) {
                        if (!confirm(alert_require_decimals.replace('<field name>', nextSibling.firstChild.nodeValue))) {
                            result = false;
                        }
                    }
                }
            }
        }

        // validate the field is money format
        if ((nextSibling.className == "moneyformat")) {
            var regfloat  = /^[0-9]*(\.[0-9]+)?$/;
            var letter = element.value;
            if (letter.substr(0,1) == "$") {
                letter = letter.substr(1,letter.length-1);
            }
            else{
                alert(alert_money_format_incorrect.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }

            if (result && !regfloat.test(letter)) {
                alert(alert_money_format_incorrect.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
            else if (result && letter <= 0) {
                alert(alert_require_positive.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
        }

        // validate the field is int format
        if ((nextSibling.className == "phone")) {
            var reg  =  /^[0-9*() \-]+(\-[0-9]+)?$/;
            result = (reg.test(element.value));
            if (!reg.test(element.value)) {
                alert(alert_input_phone);
                result = false;
            }
        }

        if (("numberformat" == nextSibling.className || "nonegetiveintformat" == nextSibling.className)) {
            var regint  = /^[0-9]*$/;
            if (!regint.test(element.value)) {
                ("nonegetiveintformat" == nextSibling.className)
                      ? alert(alert_require_none_negative_integer.replace('<field name>', nextSibling.firstChild.nodeValue))
                      : alert(alert_require_interger.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
            else {
                if (element.intlength) {
                    var intlength = parseInt(element.intlength);
                    var max  = Math.pow(2,intlength);
                    if (parseFloat(element.value) > max-1) {
                        alert(alert_big.replace('<field name>', nextSibling.firstChild.nodeValue));
                        result = false;
                    }
                }
            }
        }

        // validate whether the field is hourformat or not
        if ((nextSibling.className == "hourformat")) {
            var regint  = /^[1-9][0-4]*$/;
            if (!((regint.test(element.value)) && ((1 <= element.value) && (24 >= element.value)))) {
                alert(alert_require_hour.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
        }

        // validate whether the field is hourformat or not
        if ((nextSibling.className == "maxadcodeformat")) {
            var regint  = /^[1-9][0-9]*$/;
            if (!((regint.test(element.value)) && ((5000 <= element.value) && (65535 > element.value)))) {
                alert(alert_require_max_code.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
        }

        // validate whether the field is hourformat or not
        if ((nextSibling.className == "maxmedianumformat")) {
            var regint  = /^[1-9][0-9]*$/;
            if (!((regint.test(element.value)) && (4 <= element.value))) {
                alert(alert_require_media_num.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
        }

        // validate whether the field is hourformat or not
        if ((nextSibling.className == "maxProductNumFormat")) {
            var regint  = /^[1-9][0-9]*$/;
            if (!((regint.test(element.value)) && ((1 <= element.value) && (26 >= element.value)))) {
                alert(alert_require_product_num.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
        }

        // validate the field is int format
        if ((nextSibling.className == "intformat")) {
            var regint  = /^[1-9][0-9]*$/;
            if (!regint.test(element.value)) {
                if (!(element.canBeZero && '0' === element.value)) {
                    alert(alert_require_interger.replace('<field name>', nextSibling.firstChild.nodeValue));
                    result = false;
                }
            }
            else {
                if (!checkRange(element, alert_integer)) {
                    result = false;
                }
                if (result && element.intlength) {
                    var intlength = parseInt(element.intlength);
                    var max  = Math.pow(2,intlength);
                    if (parseFloat(element.value) > max-1) {
                        alert(alert_big.replace('<field name>', nextSibling.firstChild.nodeValue));
                        result = false;
                    }
                }
            }
        }

        // validate whether the field is color format or not
        if ((nextSibling.className == "colorformat")) {
            var reg = /^#[0-9a-fA-F]{6}$/;
            var elementValue = Trim(element.value);
            if (!reg.test(elementValue) && ("TRANSPARENT" != elementValue.toUpperCase())) {
                alert(alert_color_incorrect.replace('<field name>', nextSibling.firstChild.nodeValue));
                result = false;
            }
        }

        if (!result) {
            focusElement(element);
        }
    }

    return result;

    /**
     * Closure function to check the range for the int, float.
     */
    function checkRange(element, type) {
        var range = element.getAttribute("_range");
        var value = parseFloat(element.value);
        var result = true;
        if (range) {
            var reg = /^(\[|\()(\d*[\.?\d+]*),\s(\d*[\.?\d+]*)(\]|\))$/;
            var matched = range.match(reg);
            if (matched) {
                var minClosure = '';
                var maxClosure = '';
                if ('(' == matched[1]) {
                    if (matched[2] >= value) {
                        result = false;
                    }
                    minClosure = alert_excluded;
                }
                else if ('[' == matched[1]) {
                    if (matched[2] > value) {
                        result = false;
                    }
                    minClosure = alert_included;
                }

                if (')' == matched[4]) {
                    if (matched[3] <= value) {
                        result = false;
                    }
                    maxClosure = alert_excluded;
                }
                else if (']' == matched[4]) {
                    if (matched[3] < value) {
                        result = false;
                    }
                    maxClosure = alert_included;
                }

                if (!result) {
                    (type)
                        ? alert(alert_should_between_and.replace('<field name>', element.nextSibling.firstChild.nodeValue).replace('<type>', type).replace('<min num>', matched[2]).replace('<max num>', matched[3]).replace('<minClosure>', minClosure).replace('<maxClosure>', maxClosure))
                        : alert(alert_float_should_between_and.replace('<field name>', element.nextSibling.firstChild.nodeValue).replace('<min num>', matched[2]).replace('<max num>', matched[3]).replace('<minClosure>', minClosure).replace('<maxClosure>', maxClosure));
                }
            }
        }

        return result;
    }
}

function focusElement(element) {
    try {
        window.setTimeout( function(){element.focus();}, 0);
    } catch (e) {
        //do nothing
    }
}

/**
 * Check whether the date is a valid date.
 */
function checkDateValid(date) {
    var valid = true;
    var dateArray = date.split('-');
    var year = dateArray[0];
    var month = dateArray[1];
    var day = dateArray[2];
    var feb = ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) ? 29 : 28;
    var array = new Array(31, feb, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
    var maxday = array[month - 1];

    if (12 < month || maxday < day || 1 > month || 1 > day) {
        valid = false;
    }

    var currentDate = new Date(year, month, day);
    var minDate = new Date(1970, 1, 2);
    var maxDate = new Date(2038, 1, 1);
    if ((minDate.getTime() > currentDate.getTime()) || (maxDate.getTime() < currentDate.getTime())) {
        valid = false;
    }

    return valid;
}

function checkStartEndDate(theFrom) {
    var result = true;
    var regExp = /[-]/g;
    var startDate = theFrom.start.value.replace(regExp, '/');
    var endDate = theFrom.end.value.replace(regExp, '/');
    var dateStart = new Date(startDate);
    var dateEnd = new Date(endDate);

    if (dateStart > dateEnd) {
        alert(alert_start_later_end);
        result =  false;
    }

    return result;
}

/**
 * Check whether a character is blank (space, tab, or return).
 */
function isBlankCharacter(ch) {
    return (ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == '\n');
}

/**
 * Check whether a string is nonempty and has blank trailing (space, tab, or return).
 */
function isGeneralName(name) {
    return (name.length > 0) && !isBlankCharacter(name.charAt(0)) && !isBlankCharacter(name.charAt(name.length - 1));
}

/**
 * Deletes left space.
 */
function LTrim(str) {
    var whitespace = new String(" \t\n\r");
    var s = new String(str);
    if (whitespace.indexOf(s.charAt(0)) != -1) {
        var j=0, i = s.length;
        while (j < i && whitespace.indexOf(s.charAt(j)) != -1) {
            j++;
        }
        s = s.substring(j, i);
    }
    return s;
}

/**
 * Deletes right space.
 */
function RTrim(str) {
    var whitespace = new String(" \t\n\r");
    var s = new String(str);
    if (whitespace.indexOf(s.charAt(s.length-1)) != -1) {
        var i = s.length - 1;
        while (i >= 0 && whitespace.indexOf(s.charAt(i)) != -1) {
            i--;
        }
        s = s.substring(0, i+1);
    }
    return s;
}

/**
 * Deletes left and right space.
 */
function Trim(str) {
    return RTrim(LTrim(str));
}

/**
 * Credit cart validater in client.
 */
function isVisa(cc){ // 4111 1111 1111 1111
    if (((cc.length >= 13) && (cc.length <= 19)) && (cc.substring(0,1) == 4))
        return isCreditCard(cc);
    return false;
}

function isMasterCard(cc){ // 5500 0000 0000 0004
    firstdig = cc.substring(0,1);
    seconddig = cc.substring(1,2);
    if (((cc.length >= 13) && (cc.length <= 19)) && (firstdig == 5) && ((seconddig >= 1) && (seconddig <= 5)))
        return isCreditCard(cc);
    return false;
}

function isAmex(cc){ // 340000000000009
    firstdig = cc.substring(0,1);
    seconddig = cc.substring(1,2);
    if ((cc.length == 15) && (firstdig == 3) && ((seconddig == 4) && (seconddig == 7)))
        return isCreditCard(cc);
    return false;
}

function isDiscover(cc){ // 6011000000000004
    prefix = cc.substring(0,4);
    if ((cc.length == 16) && (prefix == 6011))
        return isCreditCard(cc);
    return false;
}

function isCreditCard(st){
    // Encoding only works on cards with less than 19 digits
    if (st.length > 19)
        return (false);
    return (true);
}

function creditCardValidator (creditCardNo) {
    var result = false;
    if (isVisa(creditCardNo)) {
        result = true;
    }
    else if (isMasterCard(creditCardNo)) {
        result = true;
    }
    else if (isAmex(creditCardNo)) {
        result = true;
    }
    else if (isDiscover(creditCardNo)) {
        result = true;
    }
    else {
        result = true;
    }
    return result;
}

/**
 * Get year, month, day array by parsing date string.
 */
function getYMDDate(date, separator, sequence) {
    var dateArray = date.split(separator);
    var yearIndex = sequence.indexOf("y");
    var monthIndex = sequence.indexOf("m");
    var dayIndex = sequence.indexOf("d");
    var ymdArray = new Array(3);

    ymdArray[0] = dateArray[yearIndex];
    ymdArray[1] = dateArray[monthIndex];
    ymdArray[2] = dateArray[dayIndex];

    return ymdArray;
}

/**
 * Check the expiratin date which in array form.
 */
function checkExpirationDate(dates) {
    dateCurrent = new Date();
    dateCurrent = new Date(dateCurrent.getFullYear() + '/' + (dateCurrent.getMonth() + 1) + '/01');
    dateExp = new Date(dates[0] + '/' + dates[1] + '/01');
    if (dateCurrent > dateExp) {
        alert(alert_expiration_date_incorrect);
        return false;
    }

    return true;
}

/**
 * Atom function to check string is a valid URL.
 */
function isUrl(url) {
    var regUrl = /^(http|https):\/\//;
    return regUrl.test(Trim(url));
}
